﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace AutoFolderStructurePrinter
{
   public partial class Form1 : Form
   {
      private const int ButtonYCoord = 92;
      private const int BackButtonXCoord = 300;
      private const int NextButtonXCoord = 376;
      private const int CancelButtonXCoord = 470;

      private string targetLocation;
      private int currentPageIndex;
      private string saveLocation;
      private string tempFileData;
      private string[] filterExts;

      public Form1()
      {
         InitializeComponent();

         targetLocation = "C:\\";
         saveLocation = "C:\\temp.txt";
         currentPageIndex = 0;
         tempFileData = "";
         filterExts = new String[0];

         saveFileDialog1.Filter = "Text Document (*.txt)|*.txt|All Files (*.*)|*.*";
         saveFileDialog1.FilterIndex = 1;
      }

      private void Form1_Load(object sender, EventArgs e)
      {
         Show();

         folderBrowserDialog1.Description = "Select the folder you want the wizard to list the structure";
         folderBrowserDialog1.ShowNewFolderButton = false;
         DialogResult result = folderBrowserDialog1.ShowDialog();

         if (result == DialogResult.OK)
         {
            targetLocation = folderBrowserDialog1.SelectedPath;
            locationTextBox.Text = targetLocation;
            TopMost = true;

            ChangeSaveDetails();
         }
         else
         {
            Close();
         }

         foreach (TabPage page in wizardPages1.TabPages)
         {
            Button backButton = new Button();
            backButton.Location = new Point(BackButtonXCoord, ButtonYCoord);
            backButton.Name = page.Text + "BackButton";
            backButton.Size = new Size(75, 23);
            backButton.TabIndex = 3;
            backButton.Text = "< Back";
            backButton.UseVisualStyleBackColor = true;
            backButton.Click += new System.EventHandler(this.backButton_Click);

            Button nextButton = new Button();
            nextButton.Location = new Point(NextButtonXCoord, ButtonYCoord);
            nextButton.Name = page.Text + "NextButton";
            nextButton.Size = new Size(75, 23);
            nextButton.TabIndex = 4;
            nextButton.Text = "Next >";
            nextButton.UseVisualStyleBackColor = true;
            nextButton.Click += new System.EventHandler(this.nextButton_Click);

            Button cancelButton = new Button();
            cancelButton.Location = new Point(CancelButtonXCoord, ButtonYCoord);
            cancelButton.Name = page.Text + "CancelButton";
            cancelButton.Size = new Size(75, 23);
            cancelButton.TabIndex = 5;
            cancelButton.Text = "Cancel";
            cancelButton.UseVisualStyleBackColor = true;
            cancelButton.Click += new System.EventHandler(this.cancelButton_Click);

            page.Controls.Add(backButton);
            page.Controls.Add(nextButton);
            page.Controls.Add(cancelButton);

            if (page.Text == "selection")
            {
               backButton.Enabled = false;
            }
            else if (page.Text == "save")
            {
               nextButton.Text = "Generate";
            }

            else if (page.Text == "finish")
            {
               backButton.Enabled = false;
               cancelButton.Enabled = false;
               nextButton.Text = "Finish";
            }

            backButton.BringToFront();
            nextButton.BringToFront();
            cancelButton.BringToFront();
         }
      }

      private void cancelButton_Click(object sender, EventArgs e)
      {
         Close();
      }

      private void changeButton_Click(object sender, EventArgs e)
      {
         DialogResult result = folderBrowserDialog1.ShowDialog();

         if (result == DialogResult.OK)
         {
            targetLocation = folderBrowserDialog1.SelectedPath;
            locationTextBox.Text = targetLocation;
            TopMost = true;

            ChangeSaveDetails();
         }
      }

      private void nextButton_Click(object sender, EventArgs e)
      {
         bool quit = false;
         currentPageIndex++;
         if (wizardPages1.SelectedTab.Text == "selection")
         {
            targetLocation = locationTextBox.Text;
            if (ValidateSelectedDirectory(targetLocation))
            {
               ChangeSaveDetails();
            }
            else
            {
               MessageBox.Show("The selected folder does not exist.", "Invalid folder", MessageBoxButtons.OK, MessageBoxIcon.Error);
               currentPageIndex--;
            }
         }
         else if (wizardPages1.SelectedTab.Text == "options")
         {
            filterExts = fileExtTextBox.Text.Split(';');
            foreach (string ext in filterExts)
            {
               Console.WriteLine(ext);
            }

         }
         else if (wizardPages1.SelectedTab.Text == "save")
         {
            saveLocation = saveTextBox.Text;
            if (ValidateSaveDirectory(saveLocation))
            {
               GenerateFile();
            }
            else
            {
               MessageBox.Show("The current save path is not valid.", "Invalid path", MessageBoxButtons.OK, MessageBoxIcon.Error);
               currentPageIndex--;
            }
         }
         else if (wizardPages1.SelectedTab.Text == "finish")
         {
            if (quitRadioButton.Checked)
            {
               quit = true;
            }
            else if (restartRadioButton.Checked)
            {
               currentPageIndex = 0;
            }
         }

         if (quit)
         {
            Close();
         }
         else
         {
            wizardPages1.SelectTab(currentPageIndex);
         }
      }

      private void backButton_Click(object sender, EventArgs e)
      {
         currentPageIndex--;
         if (wizardPages1.SelectedTab.Text == "options")
         {
            wizardPages1.SelectTab(currentPageIndex);
         }
         else if (wizardPages1.SelectedTab.Text == "save")
         {
            wizardPages1.SelectTab(currentPageIndex);
         }
      }

      private bool ValidateSelectedDirectory(string path)
      {
         bool exists = false;

         DirectoryInfo dirInfo = new DirectoryInfo(path);

         if (dirInfo.Exists)
         {
            exists = true;
         }

         return exists;
      }

      private void changeSaveButton_Click(object sender, EventArgs e)
      {
         DialogResult result = saveFileDialog1.ShowDialog();

         if (result == DialogResult.OK)
         {
            saveLocation = saveFileDialog1.FileName;
            saveTextBox.Text = saveLocation;
         }
      }

      private void ChangeSaveDetails()
      {
         int fileNumber = 1;
         string savePath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
         DirectoryInfo dirInfo = new DirectoryInfo(targetLocation);
         string saveFileName = "";
         if (CheckRoot(targetLocation))
         {
            DriveInfo driveInfo = new DriveInfo(targetLocation);
            saveFileName = driveInfo.VolumeLabel;
         }
         else
         {
            saveFileName = dirInfo.Name;
         }
         saveLocation = savePath + "\\" + saveFileName + " (Folder List) " + fileNumber + ".txt";
         FileInfo fileInfo = new FileInfo(saveLocation);
         while (fileInfo.Exists)
         {
            fileNumber++;
            saveLocation = savePath + "\\" + saveFileName + " (Folder List) " + fileNumber + ".txt";
            fileInfo = new FileInfo(saveLocation);
         }
         saveTextBox.Text = saveLocation;
         saveFileDialog1.InitialDirectory = savePath;
         saveFileDialog1.FileName = saveFileName + " (Folder List) " + fileNumber + ".txt";
      }

      private void GenerateFile()
      {
         tempFileData = "";
         DirectoryInfo dirInfo = new DirectoryInfo(targetLocation);
         ArrayList drawHierarchy = new ArrayList();
         RecurseFolders(dirInfo, drawHierarchy);

         if (saveRadioButton.Checked)
         {
            SaveToFile();
         }
         else if (printRadioButton.Checked)
         {
            PrintToFile(/*true*/);
         }
         else if (savePrintRadioButton.Checked)
         {
            SaveToFile();
            PrintToFile(/*false*/);
         }
      }

      private void RecurseFolders(DirectoryInfo dirInfo, ArrayList drawHierarchy)
      {
         AddHierarchyChars(drawHierarchy);
         tempFileData += (dirInfo.Name + "\r\n");

         DirectoryInfo[] subDirs = dirInfo.GetDirectories();
         foreach (DirectoryInfo subDir in subDirs)
         {
            if (treeStructCheckBox.Checked)
            {
               if (subDir.Name.Equals(subDirs[subDirs.Length - 1].Name))
               {
                  drawHierarchy.Add(true);
               }
               else
               {
                  drawHierarchy.Add(false);
               }
            }
            
            RecurseFolders(subDir, drawHierarchy);

            if (includeFilesCheckBox.Checked)
            {
               FileInfo[] files = subDir.GetFiles();

               if (treeStructCheckBox.Checked)
               {
                  // bug here
                  if (subDir.Name.Equals(subDirs[subDirs.Length - 1].Name))
                  //if (files.Length == 1)
                  {
                     drawHierarchy.Add(true);
                  }
                  else
                  {
                     drawHierarchy.Add(false);
                  }
               }

               //FileInfo[] files = subDir.GetFiles();

               foreach (FileInfo file in files)
               {
                  if (treeStructCheckBox.Checked)
                  {
                     if (file.Name.Equals(files[files.Length - 1].Name))
                     {
                        drawHierarchy.Add(true);
                     }
                     else
                     {
                        drawHierarchy.Add(false);
                     }
                  }

                  if (fileExtCheckBox.Checked)
                  {
                     if (ValidateFileExt(file.Extension))
                     {
                        AddHierarchyChars(drawHierarchy);
                        tempFileData += (file.Name + "\r\n");
                     }
                  }
                  else
                  {
                     AddHierarchyChars(drawHierarchy);
                     tempFileData += (file.Name + "\r\n");
                  }

                  if (drawHierarchy.Count > 0)
                  {
                     drawHierarchy.RemoveAt(drawHierarchy.Count - 1);
                  }
               }

               if (drawHierarchy.Count > 0)
               {
                  drawHierarchy.RemoveAt(drawHierarchy.Count - 1);
               }
            }
         }

         if (drawHierarchy.Count > 0)
         {
            drawHierarchy.RemoveAt(drawHierarchy.Count - 1);
         }
         
      }

      private void AddHierarchyChars(ArrayList drawHierarchy)
      {
         for (int i = 0; i < drawHierarchy.Count; i++)
         {
            bool draw = (bool) drawHierarchy[i];
            if (i == (drawHierarchy.Count - 1))
            {
               if (draw)
               {
                  tempFileData += "  \u2514\u2500\u2500";
               }
               else
               {
                  tempFileData += "  \u251C\u2500\u2500";
               }
            }
            else
            {
               if (draw)
               {
                  tempFileData += "     ";
               }
               else
               {
                  tempFileData += "  \u2502  ";
               }
            }
         }
      }

      private bool ValidateSaveDirectory(string path)
      {
         string pattern = @"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$";
         Regex reg = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
         return reg.IsMatch(path);
      }

      private bool CheckRoot(string path)
      {
         return path.Equals(Path.GetPathRoot(path));
      }

      private void SaveToFile()
      {
         StreamWriter writer = new StreamWriter(saveLocation);
         writer.Write(tempFileData);
         writer.Close();
      }

      private void PrintToFile(/*bool tempSave*/)
      {
         PageSettings pgSettings = new PageSettings();
         printDocument1.DefaultPageSettings = pgSettings;

         PrinterSettings pSettings = new PrinterSettings();
         printDialog1.PrinterSettings = pSettings;

         string[] subNames = saveLocation.Split('\\');
         printDocument1.DocumentName = subNames[subNames.Length - 1];
         printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);

         printDialog1.Document = printDocument1;

         DialogResult result = printDialog1.ShowDialog();

         if (result == DialogResult.OK)
         {
            printDocument1.Print();
         }
      }

      private void printDocument1_PrintPage(Object sender, PrintPageEventArgs e)
      {
         int charactersOnPage = 0;
         int linesPerPage = 0;

         Font printFont = new Font("Courier New", 12);

         // Sets the value of charactersOnPage to the number of characters 
         // of stringToPrint that will fit within the bounds of the page.
         e.Graphics.MeasureString(tempFileData, printFont,
             e.MarginBounds.Size, StringFormat.GenericTypographic,
             out charactersOnPage, out linesPerPage);

         // Draws the string within the bounds of the page
         e.Graphics.DrawString(tempFileData, printFont, Brushes.Black,
             e.MarginBounds, StringFormat.GenericTypographic);

         // Remove the portion of the string that has been printed.
         tempFileData = tempFileData.Substring(charactersOnPage);

         // Check to see if more pages are to be printed.
         e.HasMorePages = (tempFileData.Length > 0);
      }

      private void includeFilesCheckBox_CheckedChanged(object sender, EventArgs e)
      {
         if (includeFilesCheckBox.Checked)
         {
            fileExtCheckBox.Enabled = true;
            fileExtTextBox.Enabled = true;
         }
         else
         {
            fileExtCheckBox.Enabled = false;
            fileExtTextBox.Enabled = false;
            fileExtCheckBox.Checked = false;
         }
      }

      private bool ValidateFileExt(string extension)
      {
         bool result = false;
         foreach (string ext in filterExts)
         {
            if (extension.Equals(ext, StringComparison.CurrentCultureIgnoreCase))
            {
               result = true;
               break;
            }
         }

         return result;
      }
   }
}
